package com.zhy.changeskin;


import com.zhy.changeskin.attr.SkinAttrSupport;
import com.zhy.changeskin.attr.SkinView;
import com.zhy.changeskin.callback.ISkinChangingCallback;
import com.zhy.changeskin.utils.MediaUtil;
import com.zhy.changeskin.utils.PrefUtils;
import com.zhy.changeskin.utils.TextUtils;
import ohos.aafwk.ability.AbilitySlice;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class SkinManager
{
    private Context mContext;
    private PrefUtils mPrefUtils;

    private boolean usePlugin;

    private String mSuffix = "";
    private String mCurPluginPath;
    private HashMap<String, String> mImageMap;


    private HashMap<AbilitySlice, ComponentContainer> mAbilitySlices = new HashMap<AbilitySlice, ComponentContainer>();
    private static final String TAG = SkinManager.class.getSimpleName();
    private EventHandler eventHandler;

    private SkinManager() {
    }

    private static class SingletonHolder {
        static SkinManager sInstance = new SkinManager();
    }

    public static SkinManager getInstance()
    {
        return SingletonHolder.sInstance;
    }


    public void init(Context context) {
        mContext = context.getApplicationContext();
        mPrefUtils = new PrefUtils(mContext);
        String skinPluginPath = mPrefUtils.getPluginPath();
        mSuffix = mPrefUtils.getSuffix();
        eventHandler = new EventHandler(EventRunner.getMainEventRunner());
        try {
            if (skinPluginPath != null && !TextUtils.isEmpty(skinPluginPath)) {
                loadPlugin(skinPluginPath);
                mCurPluginPath = skinPluginPath;
            }
        } catch (Exception e) {
            mPrefUtils.clear();
            e.printStackTrace();
        }
    }

    public void removeAnySkin() {
        clearPluginInfo();
        notifyChangedListeners();
    }


    public boolean needChangeSkin()
    {
        return usePlugin || !TextUtils.isEmpty(mSuffix);
    }


    public ResourceManager getResourceManager() {
        return new ResourceManager(mContext, mSuffix);
    }


    /**
     * 应用内换肤，传入资源区别的后缀
     *
     * @param suffix
     */
    public void changeSkin(String suffix) {
        clearPluginInfo();//clear before
        mSuffix = suffix;
        mPrefUtils.putPluginSuffix(suffix);
        notifyChangedListeners();
    }

    private void clearPluginInfo() {
        mCurPluginPath = null;
        usePlugin = false;
        mSuffix = null;
        mPrefUtils.clear();
    }

    private void updatePluginInfo(String skinPluginPath, String suffix) {
        mPrefUtils.putPluginPath(skinPluginPath);
        mPrefUtils.putPluginSuffix(suffix);
        mCurPluginPath = skinPluginPath;
        mSuffix = suffix;
    }

    public void changeSkin(final String skinPluginFolder, ISkinChangingCallback callback) {
        changeSkin(skinPluginFolder, "", callback);
    }


    /**
     * 根据suffix选择插件内某套皮肤，默认为""
     *
     * @param skinPluginFolder
     * @param suffix
     * @param callback
     */
    public void changeSkin(final String skinPluginFolder, final String suffix, ISkinChangingCallback callback) {
        if (callback == null)
            callback = ISkinChangingCallback.DEFAULT_SKIN_CHANGING_CALLBACK;
        final ISkinChangingCallback skinChangingCallback = callback;

        skinChangingCallback.onStart();

        try {
            ExecutorService executor = Executors.newSingleThreadExecutor();
            EventHandler eventHandler = new EventHandler(EventRunner.getMainEventRunner());

            executor.execute(() -> {
                HashMap<String, String> imageRes = loadPlugin(skinPluginFolder);
                eventHandler.postSyncTask(() -> {
                    if (imageRes.size() != 0) {
                        SkinManager.this.updatePluginInfo(skinPluginFolder, suffix);
                        SkinManager.this.notifyChangedListeners();
                        skinChangingCallback.onComplete();
                    } else {
                        skinChangingCallback.onError(new RuntimeException("checkPlugin error occured"));
                    }
                });
            });
        } catch (Exception e) {
            e.printStackTrace();
            skinChangingCallback.onError(e);
        }
    }


    public void apply(ComponentContainer rootLayout) {
        List<SkinView> skinViews = SkinAttrSupport.getSkinViews(rootLayout);
        if (skinViews == null) return;
        for (SkinView skinView : skinViews) {
            skinView.apply();
        }
    }

    public void register(final AbilitySlice abilitySlice, ComponentContainer rootLayout) {
        mAbilitySlices.put(abilitySlice, rootLayout);
        eventHandler.postTask(new Runnable() {
            @Override
            public void run() {
                apply(rootLayout);
            }
        });
    }

    public void unregister(AbilitySlice abilitySlice) {
        mAbilitySlices.remove(abilitySlice);
    }

    public void notifyChangedListeners() {
        for (AbilitySlice ability : mAbilitySlices.keySet()) {
            apply(mAbilitySlices.get(ability));
        }
    }

    /**
     * apply for dynamic construct view
     *
     * @param view
     */
    public void injectSkin(Component view) {
        List<SkinView> skinViews = new ArrayList<SkinView>();
        SkinAttrSupport.addSkinViews(view, skinViews);
        for (SkinView skinView : skinViews) {
            skinView.apply();
        }
    }


    private HashMap<String, String> loadPlugin(String skinPluginFolder) {
        MediaUtil mUtil = new MediaUtil();
        mImageMap = mUtil.queryMedia(skinPluginFolder, mContext);
        if (mImageMap.size() != 0) {
            usePlugin = true;
        }
        return mImageMap;
    }

    public HashMap<String, String> getResourceMap() {
        return mImageMap;
    }

    public boolean isUsePlugin() {
        return usePlugin;
    }
}
